package csci5828.servlet;

import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.log4j.Logger;

import com.google.gson.Gson;

import csci5828.search.SearchResults;
import csci5828.tasks.RequestId;
import csci5828.tasks.TaskManager;
import csci5828.tasks.TaskResults;

public class LongPollingSearchResultsServlet extends HttpServlet {
	
	private static final long serialVersionUID = 1L;
	
	private final Logger logger = Logger.getLogger(getClass());

	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		// Get a handle to the global search task manager
		TaskManager<SearchResults> taskManager = TaskManagerUtil.getSearchTaskManager(getServletContext());
		if (taskManager == null) {
			req.setAttribute(RequestAttributes.ERRORS, "Task manager is uninitialized!");
			return;
		}
		
		// Get a PrintStream to write the output
		PrintStream out = new PrintStream(resp.getOutputStream());
		
		// We deliver content (search results) as JSON; set the correct mime type in the Content-Type header
		resp.setContentType("application/json");
		// This is needed to prevent the web browser from caching the response.
		resp.setHeader("Cache-Control", "no-cache");
		
		// Get the requestId parameter
		String requestIdStr = req.getParameter("requestId");
		if (requestIdStr == null) {
			out.println("Invalid request id "+requestIdStr);
			resp.setStatus(403);
			out.close();
			return;
		}
		
		// Get the wait parameter
		String waitStr = req.getParameter("wait");
		boolean wait = Boolean.valueOf(waitStr);
		
		logger.info("requestId="+requestIdStr+", wait="+wait);
		
		RequestId requestId = new RequestId(Long.valueOf(requestIdStr));
		TaskResults<SearchResults> taskResults = taskManager.getResults(requestId);
    		
		// Check if the user gave us a requestId that doesn't exist.
		if (taskResults == null) {
			out.println("Invalid request id "+requestIdStr);
			resp.setStatus(403);
			out.close();
			return;
		}
    		
		Gson gson = new Gson();
    		
		// Result object
		Map<String,Object> resultMap = new HashMap<String,Object>();
    		
		// Print any results that are already available
		List<SearchResults> availResults = new ArrayList<SearchResults>();
		for (SearchResults result: taskResults.getAvailableResults())
			availResults.add(result);
		resultMap.put("availResults", availResults);
    		
		// If there are still pending results, and the user requested to
		// wait for the next result, then do it
		try {
    		if (taskResults.isPending()) {
    			if (wait && taskResults.next()) {
    				if (taskResults.get() != null) {
    					resultMap.put("waitResult", taskResults.get());
    				} else {
    					resultMap.put("done", Boolean.TRUE);
    				}
    			}
    		} else {
				resultMap.put("done", Boolean.TRUE);
    		}
		} catch (InterruptedException e) {
			resultMap.put("done", Boolean.TRUE);
			logger.warn("Timeout exceeded when retrieving result");
			e.printStackTrace();
		}
		
   		// Send the JSON output
		out.println(gson.toJson(resultMap));
		logger.info("done");
		out.close();
		
	}
}
